package model.cubos;

import java.util.Arrays;
import model.strategys.MyStrategys;

/**
 * Esta classe reprenta o {@link CuboMagico} mais conhecido, o 3x3x3. 
 * 
 * @author Joeffison Silvério de Andrade, 21011853, joeffisonsa@gmail.com
 * @version 1.0
 * @since 11/11/11 09:20
 */
public class CuboMagico3x3x3 implements CuboMagico {
        
        protected Adesivo[][][] cubo;
        protected MyStrategys strategy;
        
        public CuboMagico3x3x3(MyStrategys strategy) {
                this.strategy = strategy;
                this.cubo = criaCubo3x3x3(6, 3);
        }
        
        private static Adesivo[][][] criaCubo3x3x3(int n_cores, int dimensao) {
                Adesivo[][][] cube = new Adesivo[6][3][3];
                int count = 0;
                for (int i = 0; i<n_cores; i++) {
                        for (int j = 0; j<dimensao; j++) {
                                for (int k = 0; k < dimensao; k++) {
                                        cube[i][j][k] = new Adesivo(count++, Adesivo.getCores()[i]);
                                }
                        }
                }
/*              {
                 {  Primeira cor.
                    Cada número da matriz mais interna, representa uma peça. 
                  {0, 1, 2},  Primeira linha do cubo, para esta cor. 
                  {3, 4, 5},  Segunda linha do cubo, para esta cor. 
                  {6, 7, 8}   Terceira linha do cubo, para esta cor. 
                   Olhando na vertical, vemos as colunas do cubo. 
                 },
                 {  Segunda cor. 
                  {9, 10, 11},
                  {12, 13, 14},
                  {15, 16, 17}
                 },
                 {  Terceira cor. 
                  {18, 19, 20},
                  {21, 22, 23},
                  {24, 25, 26}
                 },
                 {  Quarta cor. 
                  {27, 28, 29},
                  {30, 31, 32},
                  {33, 34, 35}
                 },
                 {  Quinta cor. 
                  {36, 37, 38},
                  {39, 40, 41},
                  {42, 43, 44}
                 },
                 {  Sexta cor. 
                  {45, 46, 47},
                  {48, 49, 50},
                  {51, 52, 53}
                 }
                };
*/
                return cube;
        }
        
        @Override
        public Adesivo[][][] getCubo() {
                return this.cubo;
        }
        
        @Override
        public void resolver() {
                this.strategy.resolver(this);
        }
        
        @Override
        public String toString() {
                StringBuilder espacos = new StringBuilder(); // organizar o cubo
                for (int i = 0; i < Arrays.toString(cubo[0][0]).length(); i++) { espacos.append(" "); }
                
                StringBuilder str = new StringBuilder();
                for (int j = 0; j<cubo[0].length; j++) {
                        str.append(espacos);
                        str.append(Arrays.toString(cubo[4][j]));
                        str.append("\n");
                }
                int [] interacao_j = {3, 0, 1, 2};
                for (int i = 0; i<cubo[0].length; i++) {
                        for (int j : interacao_j) {
                                str.append(Arrays.toString(cubo[j][i]));
                        }
                        str.append("\n");
                }
                for (int j = 0; j<cubo[0].length; j++) {
                        str.append(espacos);
                        str.append(Arrays.toString(cubo[5][j]));
                        str.append("\n");
                }
                
                return str.toString();
        }
        
        @Override
        public void setToStringToColor() {
                for (int i = 0; i<6; i++) {
                        for (int j = 0; j<3; j++) {
                                for (Adesivo ads : this.cubo[i][j]) {
                                        ads.setToStringToColor();
                                }
                        }
                }
        }
        
        @Override
        public void setToStringToNumbers() {
                for (int i = 0; i<6; i++) {
                        for (int j = 0; j<3; j++) {
                                for (Adesivo ads : this.cubo[i][j]) {
                                        ads.setToStringToNumbers();
                                }
                        }
                }
        }
        
        /**
         *  Pesquisa uma peca no cubo a partir da chave passada. A primeira posicao do array representa a face, o segundo array representa a linha e o terceiro a coluna.
         * @author Pedro, 21011107, pedro.falcao.ufcg@gmail.com 
         * @param key A chave da peca a ser procurada.
         * @return Um array de inteiros representando a posicao da peca com a chave dada.
         */
        public int[] searchPiece(int key) {
                for (int i = 0; i < cubo.length; i++) {
                        for (int j = 0; j < cubo[i].length; j++) {
                                for (int k = 0; k < cubo[i][j].length; k++) {
                                        if (cubo[i][j][k].getKey() == key) {
                                                return new int[]{i,j,k};
                                        }
                                }
                        }
                } return null;
        }
        
        /**
         * Metodo que calcula a posicao correta da peca passada como parametro a partir da posicao da peca central da mesma cor.
         * @author Pedro, 21011107, pedro.falcao.ufcg@gmail.com
         * @param central A peca central da mesma cor.
         * @param aCalcular A peca cuja posicao sera calculada.
         * @return Um array de inteiros contendo a posicao correta da peca no cubo na forma [face, linha, coluna] 
         * @throws Exception Caso o numero da face seja invalido, apenas para evitar erros de semantica.
         */
        public int[] calculaPosicaoCorreta(Adesivo central, Adesivo aCalcular) throws Exception {
                int indiceDeDistancia = central.getKey() - aCalcular.getKey();
                int[] retorno = this.searchPiece(central.getKey());
                retorno[2] += indiceDeDistancia;
                while (retorno[2] < -3 || retorno[2] > 3) {
                        if (retorno[2] < -3) {
                                retorno[1]++;
                                retorno[2] += 3;
                        } else {
                                retorno[1]--;
                                retorno[2] -= 3;
                        }
                }
                while (retorno[1] < -3 || retorno[1] > 3) {
                        if (retorno[1] < -3) {
                                retorno[0]++;
                                retorno[1] += 3;
                        } else {
                                retorno[0]--;
                                retorno[1] -= 3;
                        }
                } if (retorno[0] > 6 || retorno[0] < 0) {
                        throw new Exception("Erro de semantica!");
                } return retorno;
                
        }
        
        public MyStrategys getStrategy() {
                return strategy;
        }
        
}